package com.atguigu.tingshu.common.login;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.SneakyThrows;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.condition.RequestConditionHolder;

import javax.xml.transform.Result;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/***
 * 注解切面增强
 */
@Component
@Aspect//切面

public class LoginAspect {
    @Resource
    RedisTemplate redisTemplate;
    /**
     * 登录增强
     * @param joinPoint
     * @return
     */
    @SneakyThrows
    @Around("@annotation(com.atguigu.tingshu.common.login.GuiguLogin)")
    public Object LoginAspectMethod(ProceedingJoinPoint joinPoint){
        //返回结果初始化
        Object result =null;
        //获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取方法名
        Method method = signature.getMethod();
        //获取方法注解
        GuiguLogin annotation = method.getAnnotation(GuiguLogin.class);
        //获取注解isLogin属性
        if (annotation.isLogin()) {
            //获取请求包装对象 RequestContextHolder获取请求对象
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            //获取请求对象
            HttpServletRequest request = requestAttributes.getRequest();
            //请求头token
            String token = request.getHeader("token");
            if (StringUtils.isEmpty(token)) {
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
            //token合法校验
            Long userId = null;
            try {
                //登录token合法校验
                Jwt jwt = JwtHelper.decodeAndVerify(token, new RsaVerifier(SystemConstant.PUBLIC_KEY));
                JSONObject payload = JSONObject.parseObject(jwt.getClaims());
                userId = Long.valueOf(payload.get("userId").toString());
            } catch (Exception e) {
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
            //token是私钥生成合法token但是解决多端重复登录，只记录最后一次
            //User_Login_Id_"+userInfo.getId()
            Object o = redisTemplate.opsForValue().get("User_Login_Id_" + userId);
            if (o == null||!token.equals(o.toString())) {
                throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
            }
            //校验令牌到目前为止还剩下多久过期，不足1小时，续期
            Long expire = redisTemplate.getExpire("User_Login_Id_"+userId, TimeUnit.HOURS);
            System.out.println("剩余有效期"+ expire);
            if (expire <1){
                redisTemplate.expire("User_Login_Id_"+userId, 1, TimeUnit.DAYS);
            }
            //之前方法前将USerId存储到本地线程
            AuthContextHolder.setUserId(userId);
        }
//        获取方法参数
        Object[] args = joinPoint.getArgs();
        //执行方法
        result=joinPoint.proceed(args);
        //方法执行完，删除本地线程
        AuthContextHolder.removeUserId();
        //返回
        return result;
    }
}
